/////////////////////////////////////////////////////////////////////////////
// 2023 -
//open source under Apache License Version 2.0
/////////////////////////////////////////////////////////////////////////////
//  Modifications by Kumo Inc.
// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <kmhdfs/client/galois_field.h>

namespace Hdfs {
namespace Internal {

std::mutex GaloisField::singleton_mtx;
std::map<int, std::shared_ptr<GaloisField>> GaloisField::instances;

GaloisField::GaloisField(int _fieldSize) {
    fieldSize = _fieldSize;
}

int GaloisField::getFieldSize() const {
    return fieldSize;
}

/**
 * Get the object performs Galois field arithmetic with default setting
 */
std::shared_ptr<GaloisField> GaloisField::getInstance() {
    return getInstance(DEFAULT_FIELD_SIZE, DEFAULT_PRIMITIVE_POLYNOMIAL);
}

/**
 * Get the object performs Galois field arithmetics
 *
 * @param fieldSize           size of the field
 * @param primitivePolynomial a primitive polynomial corresponds to the size
 */
std::shared_ptr<GaloisField> GaloisField::getInstance(int fieldSize, int primitivePolynomial) {
    int key = static_cast<int>(((fieldSize << 16) & 0xFFFF0000) + (primitivePolynomial & 0x0000FFFF));
    std::lock_guard<std::mutex> lk(singleton_mtx);
    std::map<int, std::shared_ptr<GaloisField>>::iterator it;
    it = instances.find(key);
    if (it != instances.end()) {
        return it->second;
    } else {
        auto res = std::shared_ptr<GaloisField>(new GaloisField(fieldSize));
        instances.insert(std::pair<int, std::shared_ptr<GaloisField>>(key, res));
        return res;
    }
}

}
}
